package com.gxar.quick.ar.server.base.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gxar.common.entity.Result;
import com.gxar.common.exception.APIRuntimeException;
import com.gxar.quick.ar.server.base.async.identify.IdentifyAsync;
import com.gxar.quick.ar.server.base.common.utils.ImageSplitUtils;
import com.gxar.quick.ar.server.base.model.ResultCodeEnum;
import com.gxar.quick.ar.server.base.model.identify.dto.PredictDTO;
import com.gxar.quick.ar.server.base.model.identify.vo.request.PredictRequest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author linsy
 * @version 1.0
 * @created 2024/4/15 14:57
 */
@Api(tags = "识别接口")
@RestController
@RequestMapping("/api/identify")
@RequiredArgsConstructor
@Slf4j
public class IdentifyController {

    private final IdentifyAsync identify;

    @ApiOperation("识别")
    @PostMapping("/predict")
    public Result<JSONArray> predict(@Valid @RequestBody PredictRequest request) {
        List<PredictDTO> dtoList = this.buildPredictDTOList(request);
        // 创建多个异步任务
        @SuppressWarnings("unchecked")
        CompletableFuture<String>[] futures = new CompletableFuture[dtoList.size()];
        for (int i = 0; i < dtoList.size(); i++) {
            futures[i] = identify.predict(dtoList.get(i).getVersion(), dtoList.get(i).getUserId(), dtoList.get(i).getImageBase64(), dtoList.get(i).getMultiResult());
        }

        // 使用 AtomicBoolean 来跟踪是否已经找到满足条件的结果
        AtomicBoolean isResultFound = new AtomicBoolean(false);
        CompletableFuture<String> foundResultFuture = new CompletableFuture<>();

        // 遍历所有异步任务
        for (CompletableFuture<String> future : futures) {
            // 使用 thenAccept 处理异步任务的结果
            future.thenAccept(response -> {
                // 如果结果满足条件且还没有找到满足条件的结果
                if (predictSuccess(response) && isResultFound.compareAndSet(false, true)) {
                    // 将满足条件的结果传递给 foundResultFuture
                    foundResultFuture.complete(response);
                }
            }).exceptionally(ex -> {
                log.info("识别异常:{}", ex.getMessage(), ex);
                throw new APIRuntimeException(ex);
            });
        }

        // 返回 foundResultFuture 的结果
        try {
            // 超过3秒没返回则超时
            String responseBody = foundResultFuture.get(3, TimeUnit.SECONDS);
            if (StringUtils.isNotBlank(responseBody)) {
                JSONArray jsonArray = new JSONArray();
                if (responseBody.startsWith("{")) {
                    jsonArray.add(JSON.parseObject(responseBody));
                    return Result.success(jsonArray);
                } else {
                    return Result.success(JSON.parseArray(responseBody));
                }
            }
        } catch (TimeoutException e) {
            log.info("识别失败超时: {}", e.getMessage(), e);
            return Result.error("Can not found!");
        } catch (Exception e) {
            log.info("识别失败异常:{}", e.getMessage(), e);
            throw new RuntimeException(e);
        }
        return Result.error("Can not found!");
    }

    /**
     * 校验识别是否成功
     *
     * @param result 结果
     * @return 响应
     */
    private static boolean predictSuccess(String result) {
        // 如果结果包含message,说明识别失败
        return !result.contains("message");
    }

    private List<PredictDTO> buildPredictDTOList(PredictRequest request) {
        String imageBase64 = request.getImageBase64();
        List<PredictDTO> predictDTOList = new ArrayList<>(4);
        PredictDTO fullDtoV1 = new PredictDTO();
        fullDtoV1.setVersion("v1");
        fullDtoV1.setUserId(request.getUserId());
        fullDtoV1.setImageBase64(imageBase64);
        predictDTOList.add(fullDtoV1);
        PredictDTO fullDtoV2 = new PredictDTO();
        fullDtoV2.setVersion("v2");
        fullDtoV2.setUserId(request.getUserId());
        fullDtoV2.setImageBase64(imageBase64);
        predictDTOList.add(fullDtoV2);
        try {
            String imageAndGetCenterBase64 = ImageSplitUtils.splitImageAndGetCenterBase64(imageBase64);
            PredictDTO splitDtoV1 = new PredictDTO();
            splitDtoV1.setVersion("v1");
            splitDtoV1.setUserId(request.getUserId());
            splitDtoV1.setImageBase64(imageAndGetCenterBase64);
            predictDTOList.add(splitDtoV1);
            PredictDTO splitDtoV2 = new PredictDTO();
            splitDtoV2.setVersion("v2");
            splitDtoV2.setUserId(request.getUserId());
            splitDtoV2.setImageBase64(imageAndGetCenterBase64);
            predictDTOList.add(splitDtoV2);
        } catch (IOException e) {
            throw new APIRuntimeException(ResultCodeEnum.IMAGE_SPLIT_FAIL);
        }
        return predictDTOList;
    }

}
